/*-----------------------------------------------------------------------------
	The contents of this file are subject to the Mozilla Public License
	Version 1.1 (the "License"); you may not use this file except in
	compliance with the License.You may obtain a copy of the License at
	http://www.mozilla.org/MPL/MPL-1.1.html
	
	Software distributed under the License is distributed on an "AS IS"
	basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
	License for the specific language governing rights and limitations
	under the License.
	
	The Original Code is Fever Framework code.
	
	The Initial Developer of the Original Code is Romain Ecarnot.
	Portions created by Initial Developer are Copyright (C) 2006
	the Initial Developer. All Rights Reserved.
	
	Contributor(s):
	
	Unless required by applicable law or agreed to in writing, software
	distributed under the License is distributed on an "AS IS" BASIS,
	WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
	See the License for the specific language governing permissions and
	limitations under the License.
-----------------------------------------------------------------------------*/

/**
 * Provides some string utilities methods.
 *
 * @author Romain Ecarnot
 */
class fever.utils.StringUtil
{
	
	//-------------------------------------------------------------------------
	// Private properties
	//-------------------------------------------------------------------------
	
	/** Defines default empty characters values */
	public static var EMPTY_CHARS : String = "\n\t\r " + chr(13) + chr(10);
	
	
	//-------------------------------------------------------------------------
	// Public API
	//-------------------------------------------------------------------------
		
	/**
	 * Replaces all occurencies of the passed-in string {@code search} with the 
	 * passed-in string {@code replaceWith} in the passed-in string {@code source}.
	 * 
	 * @param source string source
	 * @param search string to replace
	 * @param replaceWith string to insert
	 */
	public static function replace( source : String, search : String, replaceWith : String ) : String
	{
		return source.split(search).join(replaceWith);
	}
	
	/**
	 * Replaced character defined at {@code index} position in {@code source} string with passed-in 
	 * {@code replaceWith} substring.
	 * 
	 * @param source String to parse
	 * @param index Position
	 * @param replaceWith String to insert
	 */
	public static function replaceAt( source : String, index : Number, replaceWith : String ) : String
	{
		var a : Array = source.split( '' );
		a.splice( index, 1, replaceWith );
		return a.join( '' );
	}
	
	/**
	 * Inserts passed-in {@code insert} string at {@code index} position in {@code source} 
	 * string.
	 * 
	 * @param source String to parse
	 * @param index Position
	 * @param insert String to insert in source string
	 */
	public static function insertAt( source : String, index : Number, insert : String ) : String
	{
		var a : Array = source.split( '' );
		a.splice( index, 0, insert );
		return a.join( '' );
	}
	
	/**
	 * Removes passed-in {@code remvove} substring from {@code source} string.
	 * 
	 * @param source String to parse
	 * @param remove String to remove
	 */
	public static function remove( source : String, toRemove : String ) : String 
	{
		return StringUtil.replace( source, toRemove, '' );
	}
	
	/**
	 * Removes character at passed-in {@code index} position.
	 * 
	 * @param source String to parse
	 * @param index Position
	 */
	public static function removeAt( source : String, index : Number ) : String
	{
			var a : Array = source.split( '' );
			a.splice( index, 1 );
			source = a.join( '' );
			return source;
	}
	
	/**
	 * Reverses the passed-in {@code source} string.
	 * 
	 * @param source source string
	 */
	public static function reverse( source : String ) : String
	{
		var a : Array = source.split("");
		a.reverse();
		return a.join("");
	}
	
	/**
	 * Removes all empty characters, defined in {@link #EMPTY_CHARS} property, 
	 * at the beginning <strong>and</strong> end of the passed-in {@code source} 
	 * string.
	 * 
	 * @param source Source string
	 * @param chars (optional) Character list to trim. 
	 * ( default use {@link #EMPTY_CHARS} )
	 */
	public static function trim( source : String, chars : String ) : String
	{
		return leftTrim ( rightTrim(source, chars), chars );
	}
	
	/**
	 * Removes all empty characters, defined in {@link #EMPTY_CHARS} property, 
	 * at the beginning of the passed-in {@code source} string.
	 * 
	 * @param source Source string
	 * @param chars (optional) Character list to trim. 
	 * ( default use {@link #EMPTY_CHARS} )
	 */
	public static function leftTrim ( source : String, chars : String ) : String
	{
		return _leftTrimForChars(source, (chars == undefined) ? EMPTY_CHARS : chars);
	}
	
	/**
	 * Removes all empty characters, defined in {@link #EMPTY_CHARS} property, 
	 * at the end of the passed-in {@code source} string.
	 * 
	 * @param source Source string
	 * @param chars (optional) Character list to trim.
	 * ( default use {@link #EMPTY_CHARS} )
	 */
	public static function rightTrim ( source : String, chars : String ) : String
	{
		return _rightTrimForChars(source, (chars == undefined) ? EMPTY_CHARS : chars);
	}
	
	/**
	 * Returns {@code true} if  passed-in {@code source} starts with passed-in 
	 * {@code search} string.
	 * 
	 * @param source string to evaluate
	 * @param search search string
	 */
	public static function isStartingWith( source : String, search : String ) : Boolean
	{
		if (source.indexOf(search) == 0) return true;
		return false;
	}
	
	/**
	 * Returns {@code true} if passed-in {@code source} ends with passed-in 
	 * {@code search} string.
	 *
	 * @param source string to evaluate
	 * @param search search string
	 */
	public static function isEndingWith( source : String, search : String ) : Boolean
	{
		if (source.lastIndexOf(search) == (source.length - search.length)) 
			return true;
		return false;
	}
	
	/**
	 * Returns {@code true} if passed-in {@code search} string is contained on 
	 * passed-in {@code source} one.
	 */
	public static function contains( source : String, search : String ) : Boolean
	{
		return (source.indexOf(search) != -1);
	}

	/**
	 * Returns {@code true} is 2 passed string are equals.
	 * 
	 * <p>Use passed-in {@code caseSensitive} argument to use case sensitive test.
	 * 
	 * @param source1 First string
	 * @param source2 Second string to compare
	 * @param caseSensitive (optional) {@code true} to enable case sensitive 
	 * test, otherwise {@code false}
	 */
	public static function areEqual( source1 : String, source2 : String, caseSensitive : Boolean ) : Boolean
	{
		if ( caseSensitive ) return ( source1 == source2 );
		else return ( source1.toUpperCase() == source2.toUpperCase() );
	}
	
	/**
	 * Returns true if the specified string is a single space, tab, return, or 
	 * newline character.
	 * 
	 * @param char {@code String} to test
	 */
	public static function isWhiteSpace( char : String ) : Boolean
	{
		if( EMPTY_CHARS.indexOf( char.charAt(0) ) != -1 ) return true;
		return false;
	}
	
	/**
	 * Substitutes "{n}" tokens within the specified string with their respective 
	 * arguments passed in.
	 * 
	 * @param source {@code String} to parse
	 * @param ... arguments to use for substitution.
	 */
	public static function substitute( source : String ) : String
	{
		var s : String = source;
		var p : Array = arguments.slice(1);
		var l : Number = p.length;
		
		for(var i : Number = 0; i < l; i++)
		{
			source = StringUtil.replace( source, "{" + i + "}", p[i] );
		}
		
		return source;
	}
	
	/**
	 * Substitutes "{n}" tokens within the specified string with passed-in 
	 * {@code args} array content.
	 * 
	 * @param source {@code String} to parse
	 * @param array Content to use for substitution.
	 */
	public static function substituteByArray( source : String, array : Array ) : String
	{
		var s : String = source;
		var l : Number = array.length;
		
		for(var i : Number = 0; i < l; i++)
		{
			source = StringUtil.replace( source, "{" + i + "}", array[i] );
		}
		return source;
	}
	
	/**
	 * Capitalizes the first letter of passed-in {@code source} string.
	 */
	public static function uppercaseFirst( source : String ) : String
	{
		 return source.charAt(0).toUpperCase() + source.substr(1);
	}
	
	/**
	 * Capitalizes the first character of every word in the passed-in {@code source}.
	 */
	public static function uppercaseWords( source : String ) : String
	{
		var chars : Array = source.split( ' ' );
		var l : Number = chars.length;
		
		for ( var i : Number = 0; i < l; i++ )
		{
			chars[i] = StringUtil.uppercaseFirst( chars[i] );
		}
		return chars.join( ' ' );
	}
	
	/**
	 * Multiply passed-in {@code source} {@code n} times.
	 */
	public static function multiply( source : String,  n : Number) : String
	{
		var ret : String = "";
		for( var i : Number = 0; i < n ; i++ ) ret += source;
		return ret;
	}
	
	/**
	 * Forces the passed-in {@code source} to starts with {@code start} character.
	 * 
	 * <p>Use {@code check} parameter to 'leftTrim' the source before.
	 */
	public static function startWithChar( source : String, start : String, check : Boolean ) : String
	{
		if( start.length > 1 ) return source;
		
		var tmp : String = ( check ) ? 	StringUtil.leftTrim( source, EMPTY_CHARS + start ) : source;
		return ( start + tmp ); 
	}
	
	/**
	 * Forces the passed-in {@code source} to finish with {@code end} character.
	 * 
	 * <p>Use {@code check} parameter to 'rightTrim' the source before.
	 */
	public static function finishWithChar( source : String, end : String, check : Boolean ) : String
	{
		if( end.length > 1 ) return source;
		
		var tmp : String = ( check ) ? 	StringUtil.rightTrim( source, EMPTY_CHARS + end ) : source;
		return ( tmp + end ); 
	}
	
	/**
	 * Summarizes passed <code>source</code> using <code>charLength</code> chars length limit.
	 * 
	 * <p>This method use <strong>character</strong> to build the summary.
	 * 
	 * @param source Source string
	 * @param charLength Chars count limit
	 * @param removeLineBreak <code>true</code> to remove all break line in <code>source</code> string<br>
	 * ( default is <code>false</code> ) 
	 */
	public static function summarise( source : String, charLength : Number, removeLineBreak : Boolean ) : String
	{
		if( charLength > 0 )
		{
			source = StringUtil.trim( source );
			if( removeLineBreak ) source = StringUtil.replace( source, '\n', '' );
			
			var ex : Array = source.split( ' ' );
			var tL : Number = ex.length;
			var char : String = '';
			
			for( var i : Number = 0; i < tL; i++ )
			{
				var sSub : String =	ex[ i ];
				var aSub : Array =	sSub.split( '' );
				var subL : Number = aSub.length;
				
				if( char.length + subL <= charLength )
					char += ( ' ' + sSub );
				else break;
			}
			
			char = StringUtil.leftTrim( char ) + '...';
			
			return char;	
		}
		else return source;
	}
	
	/**
	 * Summarizes passed <code>source</code> using <code>wordLength</code> words length limit.
	 * 
	 * <p>This method use <strong>word</strong> to build the summary.
	 * 
	 * @param source Source string
	 * @param wordLength Words count limit
	 * @param removeLineBreak <code>true</code> to remove all break line in <code>source</code> string<br>
	 * ( default is <code>false</code> ) 
	 */
	public static function summariseWord( source : String, wordLength : Number, removeLineBreak : Boolean ) : String
	{
		if( wordLength > 0 )
		{
			source = StringUtil.trim( source );
			if( removeLineBreak ) source = StringUtil.replace( source, '\n', '' );
			
			return source.split( ' ' ).slice( 0, wordLength ).concat( '...' ).join( ' ' );
		}
		else return source;
	}
	
	/**
	 * 
	 */
	public static function formatNumber( num : Number, length : Number, char : String, right : Boolean ) : String
	{
		var nDiff : Number = length - num.toString().length;
		var sReste : String = '';
		
		if( !char ) char = ' ';
		
		if( nDiff > 0 )
		{
			for( var i : Number = 0; i < nDiff; i++ ) sReste += char;
		}
		return ( right ) ? num + sReste : sReste + num;
	}
	
	/**
	 * Buils correct application url ( removes pipe "|" if present to avoid 
	 * Firefox getURL bug ).
	 */
	public static function getCleanLocalPath( path : String ) : String
	{
		var swfUrl : String = _root._url;
		var lastSlashIndex : Number = swfUrl.lastIndexOf( '/' );
		var pipeIndex:Number = swfUrl.indexOf( '|');
		var baseUrl : String;
		
		if ( pipeIndex >= 0 )
		{
		    baseUrl = swfUrl.substring( 0, pipeIndex );
		    baseUrl += ':';
		}
		else baseUrl = '';
		
		baseUrl += swfUrl.substring( pipeIndex + 1, lastSlashIndex + 1 );
		
		return baseUrl + path;
	}
	
	
	//-------------------------------------------------------------------------
	// Private implementation
	//-------------------------------------------------------------------------
	
	private static function _leftTrimForChars (source : String, escape : String) : String {
		var i : Number = 0;
		var l : Number = source.length;
		while (i < l && escape.indexOf (source.charAt (i)) >= 0) i++;
		return (i > 0 ? source.substr (i, l) : source);
	}
	
	private static function _rightTrimForChars (source : String, escape : String) : String {
		var i : Number = 0;
		var l : Number = source.length - 1;
		while (i < l && escape.indexOf (source.charAt (l)) >= 0) l--;
		return (l >= 0 ? source.substr (i, l + 1) : source);
	}
	
	private function StringUtil() {}
	
}